using System;
using System.Collections.ObjectModel;
using ParserGenerator.Extensions;

namespace ParserGenerator.TableCompression
{
    [Serializable]
    public sealed class CompactTableRow : IEquatable<CompactTableRow>, IComparable<CompactTableRow>, IComparable
    {
        public int Number { get; }
        public ReadOnlyCollection<CompactTableCell> Cells { get; }
        public int Size => Cells.Count;
        public int Width => (Size > 0) ? Cells[Size - 1].Column - Cells[0].Column + 1 : 0;

        internal CompactTableRow(int number, ReadOnlyCollection<CompactTableCell> cells)
        {
            if (number < 0)
                throw new ArgumentOutOfRangeException(nameof(number), SR.NumberMustBeNonNegative);
            if (cells == null)
                throw new ArgumentNullException(nameof(cells));
            Number = number;
            Cells = cells;
        }

        public bool RangeEquals(CompactTableRow other)
        {
            if (other == null)
                throw new ArgumentNullException(nameof(other));
            return Size == other.Size && Width == other.Width;
        }

        public sealed override int GetHashCode()
        {
            return Cells.GetListHashCode();
        }

        public bool Equals(CompactTableRow other)
        {
            return other != null && RangeEquals(other) && Cells.ListEquals(other.Cells);
        }

        public sealed override bool Equals(object obj)
        {
            return obj != null && Equals((CompactTableRow)obj);
        }

        public int CompareTo(CompactTableRow other)
        {
            if (other == null)
                return 1;
            int t = Width.CompareTo(other.Width);
            if (t != 0)
                return -t;
            return -Size.CompareTo(other.Size);
        }

        public int CompareTo(object obj)
        {
            if (obj == null)
                return 1;
            else if (obj is CompactTableRow)
                return CompareTo((CompactTableRow)obj);
            else
                throw new ArgumentException(SR.ArgumentMustBeCompactTableRow, nameof(obj));
        }

        public sealed override string ToString()
        {
            return string.Format("{0}: Size = {1}, Width = {2}", Number, Size, Width);
        }
    }
}
